package com.general.framework.data.redis;

import com.general.framework.core.exception.Ex;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @author leejean team
 * @ClassName: RedisLock
 * @Description: redis分布式锁
 * @date 2020年10月20 12:25:14
 */
@Slf4j
public class RedisLock {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 默认获取锁等待时间,2秒
     */
    private final Long DEFAULT_WAIT_TIME = 2L;

    /**
     * 默认获取锁有效时间，5秒
     */
    private final Long DEFAULT_LEASE_TIME = 5L;


    /**
     * 开启锁
     *
     * @param lockKey  锁Key
     * @param supplier 方法主体
     * @param <T>
     * @return
     */
    public <T> T lock(final String lockKey, final Supplier<T> supplier) {
        final boolean isLock = tryLock(lockKey, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, TimeUnit.SECONDS);
        try {
            if (isLock) {
                return supplier.get();
            }
        } finally {
            unlock(lockKey);
        }
        return null;
    }

    /**
     * 获取锁
     *
     * @param lockKey 锁Key
     * @return
     */
    public boolean tryLock(final String lockKey) {
        return tryLock(lockKey, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, TimeUnit.SECONDS);
    }

    public boolean tryLock(final String lockKey, final Long leaseTime, final TimeUnit timeUnit) {
        return tryLock(lockKey, DEFAULT_WAIT_TIME, leaseTime, timeUnit);
    }

    /**
     * 尝试获取锁
     *
     * @param lockKey   锁Key
     * @param waitTime  获取锁的等待时间
     * @param leaseTime 锁的有效时间
     * @param timeUnit  时间单位
     * @return
     */
    public boolean tryLock(final String lockKey, final Long waitTime, final Long leaseTime, final TimeUnit timeUnit) {
        final RLock rLock = redissonClient.getLock(lockKey);
        try {
            final Boolean isLock = rLock.tryLock(waitTime, leaseTime, timeUnit);
            return isLock;
        } catch (InterruptedException e) {
            log.error("获取redis锁失败", e);
            throw Ex.systemError();
        }
    }

    /**
     * 释放锁
     *
     * @param lockKey 锁Key
     */
    public void unlock(String lockKey) {
        final RLock rLock = redissonClient.getLock(lockKey);
        rLock.unlock();
    }

}
